#define lib_random_c
#define LUA_LIB

extern "C" {
#include "../lua.h"
#include "../lauxlib.h"
#include "../lualib.h"

#include "../lj_def.h" // Included always for the typedefs
#include "../lj_lib.h" // Included always for the typedefs
}

#undef cast
//#define GVL_EXCLUDE_STDINT 1 // lj2 has type typedefs

#include "util.hpp"
#include <cmath>

/* ------------------------------------------------------------------------ */

LUA_CHECK_FUNC(RandomState, random, UDTYPE_RANDOM)

extern "C" {

/* ------------------------------------------------------------------------ */

#define LJLIB_MODULE_random_method

LJLIB_CF(random_method_gen)		LJLIB_REC(.)
{
  int n = (int32_t)(L->top - L->base);
  RandomState *rs = &check_random(L, 1);
  U64double u;
  double d;
  if (LJ_UNLIKELY(!rs->valid)) lj_random_init(rs, 0.0);
  u.u64 = lj_math_random_step(rs);
  d = u.d - 1.0;
  if (n > 1) {
    double r1 = lj_lib_checknum(L, 2);
    if (n == 2) {
      d = floor(d*r1) + 1.0;  /* d is an int in range [1, r1] */
    } else {
      double r2 = lj_lib_checknum(L, 3);
      d = floor(d*(r2-r1+1.0)) + r1;  /* d is an int in range [r1, r2] */
    }
  }  /* else: d is a double in range [0, 1] */
  setnumV(L->top++, d);
  return 1;
}

LJLIB_PUSH(top-1) LJLIB_SET(__index)

#define LJLIB_MODULE_random

LJLIB_PUSH(top-2) LJLIB_SET(!) // Random metatable

LJLIB_CF(random_create)
{
	void* mem = lua_create_object(L, UDTYPE_RANDOM, sizeof(RandomState));

	RandomState *r = static_cast<RandomState *>(mem);

	r->valid = 0;
	return 1;
}

#include "../lj_libdef.h"
#include "../lj_lib.h"

LUALIB_API int luaopen_random(lua_State *L)
{
	LJ_LIB_REG(L, random_method);
	LJ_LIB_REG(L, random);
	return 1;
}

} // extern "C"
